Skip to content

fix(ffi): resolve protocol-only method metadata for block parameters - #71

Merged
DjDeveloperr merged 1 commit into
refactorfrom
ffi-protocol-method-metadata
Aug 26, 2026
Merged

fix(ffi): resolve protocol-only method metadata for block parameters#71
DjDeveloperr merged 1 commit into
refactorfrom
ffi-protocol-method-metadata

Conversation

@DjDeveloperr

Copy link
Copy Markdown
Collaborator

What was broken

If a method your app calls is declared only on an Objective-C protocol
(not on any real class in the object's chain), and takes a block
parameter, calling it from JS with a plain closure threw:

Error: Native callback metadata is unavailable.

This happens whenever the class that actually implements the method
doesn't declare that conformance in a header the metadata generator
parsed -- e.g. conformance added via a category/class-extension, or a
fully private concrete class (UIViewControllerTransitionCoordinator
is the classic real-world case: every method lives on the protocol,
the concrete class is private). The only workaround was hand-supplying
the ObjC encoding: interop.Block(fn, "v@?@").

Root cause: findClassForRuntimeClass (ObjCBridge.mm) only walked the
concrete class hierarchy via class_getSuperclass, never consulting
protocol conformance, so method lookup for such selectors came up
empty and the block parameter's metadata was never resolved.

The fix

Adds a protocol-conformance fallback (class_copyProtocolList +
protocol_copyProtocolList, walked alongside the existing class walk),
consulted only once the ordinary class-hierarchy lookup misses, cached
per runtime Class so classes with complete metadata pay nothing
extra.

Duplicate-selector rule: most-derived class first, then ancestors;
within one class's own adopted-protocol list, class_copyProtocolList's
order (stable, reflects declaration order); each protocol's inherited
protocols expand depth-first before its next sibling. First match wins.

Verification

Two new fixtures (hidden vs. declared protocol conformance, same
selectors) prove the fix and that the already-working class path is
unaffected. Confirmed genuine repro: same tests fail with exactly this
error on the pre-fix code. Full macOS suite: 717 tests, 8 pre-existing
DBL_MAX-formatting failures (unchanged), 0 new failures.

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com
https://claude.ai/code/session_01BQPGUU8YECUhbBvwkW4Kek

@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d16aeb27-b992-42e1-87e9-ce86d0dc998c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

findClassForRuntimeClass only ever consulted the concrete class
hierarchy (class_getSuperclass), so a selector declared solely on a
conformed Objective-C protocol had no path to its metadata whenever the
class that actually implements it doesn't carry that conformance in a
header the metadata generator parsed -- a category/class-extension
conformance, or (as with UIViewControllerTransitionCoordinator) a fully
private concrete class. createEngineCallback then threw "Native
callback metadata is unavailable." for any block parameter on such a
method, forcing callers to hand-supply the ObjC encoding via
interop.Block(fn, "...").

Adds a runtime protocol-conformance fallback (class_copyProtocolList +
protocol_copyProtocolList, walked alongside the existing class walk),
consulted only once the ordinary class/protocol-declared-on-header
lookup misses, and cached per runtime Class so well-declared classes
pay nothing extra. Deterministic tie-break for a class conforming to
several protocols declaring the same selector: most-derived class
first, then ancestors; within one class's own adopted-protocol list,
class_copyProtocolList's order; each protocol's inherited protocols
expanded depth-first ahead of its next sibling. First match wins.

Covered by two new fixtures/tests mirroring the real-world shape
(hidden vs. declared protocol conformance) plus the existing 717-test
macOS suite (unchanged 8 pre-existing DBL_MAX failures, no new ones).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BQPGUU8YECUhbBvwkW4Kek
@DjDeveloperr
DjDeveloperr force-pushed the ffi-protocol-method-metadata branch from ce3d2a6 to dcf739e Compare August 26, 2026 00:08
@DjDeveloperr
DjDeveloperr merged commit 22bc6b7 into refactor Aug 26, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant